package com.ygq.Impl;

import BO.*;
import DO.*;
import DTO.AddTest2DTO;
import DTO.AddTestDTO;
import VO.*;
import com.ygq.PublishTestService;
import mapper.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import static com.ygq.Impl.FillEmptyQuestionServiceImpl.readFileToString;


@Service
public class PublishTestServiceImpl implements PublishTestService {

    @Autowired
    private ChooseQuestionMapper chooseQuestionMapper;

    @Autowired
    private JudgeQuestionMapper judgeQuestionMapper;

    @Autowired
    private FillEmptyQuestionMapper fillEmptyQuestionMapper;

    @Autowired
    private EncodeQuestionMapper encodeQuestionMapper;

    @Autowired
    private EncodeExampleMapper encodeExampleMapper;

    @Autowired
    private FillEmptyAnswerQuestionMapper fillEmptyAnswerQuestionMapper;


    // 测试表需要的mapper
    @Autowired
    private WorkMapper workMapper;

    @Autowired
    private WorkJudgeMapper workJudgeMapper;

    @Autowired
    private WorkFillOptionMapper workFillOptionMapper;

    @Autowired
    private WorkFillMapper workFillMapper;

    @Autowired
    private WorkFileUploadMapper workFileUploadMapper;

    @Autowired
    private WorkEncodeMapper workEncodeMapper;

    @Autowired
    private WorkClassMapper workClassMapper;

    @Autowired
    private WorkChooseMapper workChooseMapper;

    // 编程题mapper
    @Autowired
    private EncodeTestMapper encodeTestMapper;

    @Autowired
    private EncodeTestDataMapper encodeTestDataMapper;

    @Autowired
    private WorkScoreMapper workScoreMapper;


    // 获取所有编号
    public QuestionNumberVO getQuestionNumber(Integer startRange,Integer endRange) {
        QuestionNumberVO questionNumberVO = new QuestionNumberVO();
        questionNumberVO.setChooseQuestionNumber(chooseQuestionMapper.getQuestionNumberAndId(startRange,endRange));
        questionNumberVO.setJudgeQuestionNumber(judgeQuestionMapper.getQuestionNumberAndId(startRange,endRange));
        questionNumberVO.setFillEmptyQuestionNumber(fillEmptyQuestionMapper.getQuestionNumberAndId(startRange,endRange));
        questionNumberVO.setEncodeQuestionNumber(encodeQuestionMapper.getQuestionNumberAndId(startRange,endRange));
        return questionNumberVO;
    }

    // 根据id获取题目信息
    public Object getQuestion(Integer id, Integer questionType) {
        // 第一步，判断question是什么数字
        if (questionType==1){
             // 需要选择题数据
            ChooseQuestionVO chooseQuestionVO = new ChooseQuestionVO();
            ChooseQuestionDO questionDO = chooseQuestionMapper.getById(id);
            BeanUtils.copyProperties(questionDO,chooseQuestionVO);
            return chooseQuestionVO;
        } else if (questionType==2){
            // 需要判断题数据
            JudgeQuestionVO judgeQuestionVO = new JudgeQuestionVO();
            JudgeQuestionDO judgeQuestionDO = judgeQuestionMapper.getById(id);
            BeanUtils.copyProperties(judgeQuestionDO,judgeQuestionVO);
            return judgeQuestionVO;
        } else if (questionType==3) {
            // 需要程序填空题
            FillEmptyVO fillEmptyVO = new FillEmptyVO();
            FillEmptyDO fillEmptyDO = fillEmptyQuestionMapper.getById(id);
            BeanUtils.copyProperties(fillEmptyDO,fillEmptyVO);
            // 获取代码地址信息
            String address = fillEmptyDO.getAddress();
            try {
                String code = readFileToString(address);
                fillEmptyVO.setCode(code);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            // 答案信息
            // 首先， 创建一个答案集合
            List<AnswerBO> answerBOList = fillEmptyAnswerQuestionMapper.getAnswerByFEId(fillEmptyVO.getId());
            // 根据题目id从FillEmptyAnswer表中获取答案数据
            fillEmptyVO.setAnswers(answerBOList);
            return fillEmptyVO;
        } else if (questionType==4) {
            // 需要编程题
            EncodeQuestionVO encodeQuestionVO = new EncodeQuestionVO();
            EncodeQuestionDO encodeQuestionDO = encodeQuestionMapper.getById(id);
            BeanUtils.copyProperties(encodeQuestionDO,encodeQuestionVO);
            return encodeQuestionVO;
        }
        return null;
    }

    // 保存第一套测试
    @Transactional
    public void saveTest1(AddTestDTO addTestDTO) {
        WorkDO workDO = new WorkDO();
        workDO.setTitle(addTestDTO.getTitle());
        workDO.setStartRange(addTestDTO.getStartRange());
        workDO.setEndRange(addTestDTO.getEndRange());
        workDO.setChooseNumber(addTestDTO.getChoose().length);
        workDO.setChooseScore(addTestDTO.getChooseScore());
        workDO.setJudgeNumber(addTestDTO.getJudge().length);
        workDO.setJudgeScore(addTestDTO.getJudgeScore());
        workDO.setFillEmptyNumber(addTestDTO.getFillEmpty().size());
        workDO.setEncodeNumber(addTestDTO.getEncode().size());
        workDO.setFileUploadNumber(0);
        workDO.setWorkType(addTestDTO.getWorkType());
        workDO.setCreateTime(LocalDateTime.now());
        // 1 保存测试主要信息
        workMapper.save(workDO);

        // 选择题
        for (int i = 0; i < addTestDTO.getChoose().length; i++) {
            WorkChooseDO workChooseDO = new WorkChooseDO();
            workChooseDO.setWorkId(workDO.getId());
            workChooseDO.setOrder(i+1);
            workChooseDO.setChooseId(addTestDTO.getChoose()[i]);
            workChooseDO.setScore(addTestDTO.getChooseScore());
            workChooseDO.setCreateTime(LocalDateTime.now());
            // 2. 保存测试的选择题信息
            workChooseMapper.save(workChooseDO);
        }

        // 判断题
        for (int i = 0; i < addTestDTO.getJudge().length; i++) {
            WorkJudgeDO workJudgeDO = new WorkJudgeDO();
            workJudgeDO.setWorkId(workDO.getId());
            workJudgeDO.setOrder(i+1);
            workJudgeDO.setJudgeId(addTestDTO.getJudge()[i]);
            workJudgeDO.setScore(addTestDTO.getJudgeScore());
            workJudgeDO.setCreateTime(LocalDateTime.now());
            // 3. 保存判断题信息
            workJudgeMapper.save(workJudgeDO);
        }

        // 程序填空题
        for (int i = 0; i < addTestDTO.getFillEmpty().size(); i++) {
            WorkFillDO workFillDO = new WorkFillDO();
            workFillDO.setWorkId(workDO.getId());
            workFillDO.setOrder(i+1);
            workFillDO.setFillEmptyId(addTestDTO.getFillEmpty().get(i).getId());
            workFillDO.setOptions(addTestDTO.getFillEmpty().get(i).getScores().size());
            workFillDO.setScores(addTestDTO.getFillEmpty().get(i).getScoresview());
            workFillDO.setCreateTime(LocalDateTime.now());
            // 4. 保存填空题信息
            workFillMapper.save(workFillDO);

            // 程序填空的分值
            for (int j = 0; j < addTestDTO.getFillEmpty().get(i).getScores().size(); j++) {
                WorkFillOptionDO workFillOptionDO = new WorkFillOptionDO();
                workFillOptionDO.setWorkId(workDO.getId());
                workFillOptionDO.setWorkFillId(workFillDO.getId());
                workFillOptionDO.setOption(addTestDTO.getFillEmpty().get(i).getScores().get(j).getOrder());
                workFillOptionDO.setScore(addTestDTO.getFillEmpty().get(i).getScores().get(j).getScore());
                workFillOptionDO.setCreateTime(LocalDateTime.now());
                // 4.1 保存填空题分值信息
                workFillOptionMapper.save(workFillOptionDO);
            }
        }

        // 编程题
        for (int i = 0; i < addTestDTO.getEncode().size(); i++) {
            WorkEncodeDO workEncodeDO = new WorkEncodeDO();
            workEncodeDO.setWorkId(workDO.getId());
            workEncodeDO.setOrder(i+1);
            workEncodeDO.setEncodeId(addTestDTO.getEncode().get(i).getId());
            workEncodeDO.setScore(addTestDTO.getEncode().get(i).getScore());
            workEncodeDO.setCreateTime(LocalDateTime.now());
            // 5. 保存编程题信息
            workEncodeMapper.save(workEncodeDO);
        }

        // 6.班级添加
        for (int i = 0; i < addTestDTO.getClasses().length; i++) {
            WorkClassDO workClassDO = new WorkClassDO();
            workClassDO.setWorkId(workDO.getId());
            workClassDO.setClassId(addTestDTO.getClasses()[i]);
            workClassDO.setStartTime(addTestDTO.getStartTime());
            workClassDO.setEndTime(addTestDTO.getEndTime());
            workClassDO.setCreateTime(LocalDateTime.now());
            workClassMapper.save(workClassDO);
        }
    }

    // 保存第二套测试题
    @Transactional
    public void saveTest2(AddTest2DTO addTestDTO) {
        // 主信息
        WorkDO workDO = new WorkDO();
        workDO.setTitle(addTestDTO.getTitle());
        workDO.setStartRange(addTestDTO.getStartRange());
        workDO.setEndRange(addTestDTO.getEndRange());
        workDO.setChooseNumber(0);
        workDO.setChooseScore(0.0);
        workDO.setJudgeNumber(0);
        workDO.setJudgeScore(0.0);
        workDO.setFillEmptyNumber(0);
        workDO.setEncodeNumber(0);
        workDO.setFileUploadNumber(addTestDTO.getFileUpload().size());
        workDO.setWorkType(addTestDTO.getWorkType());
        workDO.setCreateTime(LocalDateTime.now());
        workMapper.save(workDO);

        // 文件上传题信息
        for (int i = 0; i < addTestDTO.getFileUpload().size(); i++) {
            WorkFileUploadDO workFileUploadDO = new WorkFileUploadDO();
            workFileUploadDO.setWorkId(workDO.getId());
            workFileUploadDO.setOrder(addTestDTO.getFileUpload().get(i).getOrder());
            workFileUploadDO.setScore(addTestDTO.getFileUpload().get(i).getScore());
            workFileUploadDO.setDescription(addTestDTO.getFileUpload().get(i).getDescription());
            workFileUploadDO.setCreateTime(LocalDateTime.now());
            workFileUploadMapper.save(workFileUploadDO);
        }

        // 班级添加
        for (int i = 0; i <addTestDTO.getClasses().length; i++) {
            WorkClassDO workClassDO = new WorkClassDO();
            workClassDO.setWorkId(workDO.getId());
            workClassDO.setClassId(addTestDTO.getClasses()[i]);
            workClassDO.setStartTime(addTestDTO.getStartTime());
            workClassDO.setEndTime(addTestDTO.getEndTime());
            workClassDO.setCreateTime(LocalDateTime.now());
            workClassMapper.save(workClassDO);
        }
    }

    // 根据班级id获取测试信息list
    public List<WorkTestByClassIdVO> getWorkTestByClass(Integer classId,Integer userId) {
        // 创建一个DateTimeFormatter，用于自定义日期和时间格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        List<WorkTestByClassIdVO> list = new ArrayList<>();

        // 根据班级id获取到全部数据
        List<WorkClassDO> workClassDOList = workClassMapper.getByClassId(classId);
        for (WorkClassDO workClassDO : workClassDOList) {
            WorkTestByClassIdVO workTestByClassIdVO = new WorkTestByClassIdVO();
            workTestByClassIdVO.setId(workClassDO.getWorkId());
            workTestByClassIdVO.setStartTime(workClassDO.getStartTime().format(formatter));
            workTestByClassIdVO.setEndTime(workClassDO.getEndTime().format(formatter));
            int state;
            if (workClassDO.getStartTime().isAfter(LocalDateTime.now())) {
                // 开始时间在当前时间之后，表示该试卷还不能开始答题，状态为0，表示为开始
                state = 0;
            } else if (workClassDO.getEndTime().isBefore(LocalDateTime.now())) {
                // 结束时间在现在时间之后，表示以及结束了状态为2
                state = 2;
            }else {
                state = 1;
            }
            // 这个状态变量仅仅只是为了前端展示，不能作为判断依据
            workTestByClassIdVO.setState(state);

            // 接下来设置试卷标题
            WorkTypeAndTitleBO workTypeAndTitleBO = workMapper.getTitleById(workClassDO.getWorkId());
            workTestByClassIdVO.setDescription(workTypeAndTitleBO.getTitle());
            workTestByClassIdVO.setWorkType(workTypeAndTitleBO.getWorkType());
            Double scoreById = workScoreMapper.getScoreById(workClassDO.getWorkId(), userId);
            // 获取试卷分数
            workTestByClassIdVO.setScore(scoreById==null?0.0:scoreById);
            list.add(workTestByClassIdVO);
        }
        return list;
    }

    // 获取测试1的题目数据
    public WorkTestByWorkIdVO gettest1(Integer workId) {
        WorkTestByWorkIdVO workTestByWorkIdVO = new WorkTestByWorkIdVO();
        WorkDO workDO = workMapper.getByWorkId(workId);
        //设置主要信息
        workTestByWorkIdVO.setStartRange(workDO.getStartRange());
        workTestByWorkIdVO.setEndRange(workDO.getEndRange());

        workTestByWorkIdVO.setTitle(workDO.getTitle());

        workTestByWorkIdVO.setChooseNumber(workDO.getChooseNumber());
        workTestByWorkIdVO.setChooseScore(workDO.getChooseScore());

        workTestByWorkIdVO.setJudgeNumber(workDO.getJudgeNumber());
        workTestByWorkIdVO.setJudgeScore(workDO.getJudgeScore());

        workTestByWorkIdVO.setFillEmptyNumber(workDO.getFillEmptyNumber());
        workTestByWorkIdVO.setEncodeNumber(workDO.getEncodeNumber());

        // 设置选择题信息
        List<WorkChooseBO> workChooseList = new ArrayList<>();
        List<WorkChooseDO> workChooseDOList = workChooseMapper.getByWorkId(workId);
        for (WorkChooseDO workChooseDO : workChooseDOList) {
            WorkChooseBO workChooseBO = new WorkChooseBO();

            workChooseBO.setOrder(workChooseDO.getOrder());
            workChooseBO.setChooseId(workChooseDO.getChooseId());

            // 根据选择题id获取选择题数据
            ChooseQuestionDO chooseQuestionDO = chooseQuestionMapper.getById(workChooseDO.getChooseId());
            workChooseBO.setQuestionNumber(chooseQuestionDO.getQuestionNumber());
            workChooseBO.setDescription(chooseQuestionDO.getDescription());

            // 选择题答案
            ChooseOptionBO chooseOptionBO = new ChooseOptionBO();
            chooseOptionBO.setOptionA(chooseQuestionDO.getOptionA());
            chooseOptionBO.setOptionB(chooseQuestionDO.getOptionB());
            chooseOptionBO.setOptionC(chooseQuestionDO.getOptionC());
            chooseOptionBO.setOptionD(chooseQuestionDO.getOptionD());

            workChooseBO.setChooseOption(chooseOptionBO);
            workChooseList.add(workChooseBO);
        }
        workTestByWorkIdVO.setWorkChooseList(workChooseList);

        // 设置判断题
        List<WorkJudgeBO> workJudgeList = new ArrayList<>();
        List<WorkJudgeDO> workJudgeDOList = workJudgeMapper.getByWorkId(workId);
        for (WorkJudgeDO workJudgeDO : workJudgeDOList) {
            WorkJudgeBO workJudgeBO = new WorkJudgeBO();
            workJudgeBO.setOrder(workJudgeDO.getOrder());
            workJudgeBO.setJudgeId(workJudgeDO.getJudgeId());
            JudgeQuestionDO judgeQuestionDO = judgeQuestionMapper.getById(workJudgeDO.getJudgeId());
            workJudgeBO.setQuestionNumber(judgeQuestionDO.getQuestionNumber());
            workJudgeBO.setDescription(judgeQuestionDO.getDescription());
            workJudgeList.add(workJudgeBO);
        }
        workTestByWorkIdVO.setWorkJudgeList(workJudgeList);

        // 设置程序填空题
        List<WorkFillEmptyBO> workFillEmptyList = new ArrayList<>();
        List<WorkFillDO> workFillDOList = workFillMapper.getByWorkId(workId);
        for (WorkFillDO workFillDO : workFillDOList) {
            WorkFillEmptyBO workFillEmptyBO = new WorkFillEmptyBO();
            workFillEmptyBO.setOrder(workFillDO.getOrder());
            workFillEmptyBO.setScores(workFillDO.getScores());

            Integer fillEmptyId = workFillDO.getFillEmptyId();// 获取程序填空题id
            workFillEmptyBO.setFillEmptyId(fillEmptyId);

            FillEmptyDO fillEmptyDO = fillEmptyQuestionMapper.getById(fillEmptyId);
            workFillEmptyBO.setQuestionNumber(fillEmptyDO.getQuestionNumber());
            workFillEmptyBO.setDescription(fillEmptyDO.getDescription());
            try {
                String code = readFileToString(fillEmptyDO.getAddress());
                workFillEmptyBO.setCode(code);
            } catch (IOException e) {
                System.out.println("读取程序阅读题的代码片段时发生错误");
                throw new RuntimeException(e);
            }

            Integer workFillId = workFillDO.getId();// 获取试卷的填空题id
            // 根据填空题id获取选项信息
            List<WorkFillOptionDO> workFillOptionDOList = workFillOptionMapper.getByWorkFillId(workFillId);

            // 完善填空题答案信息
            List<fillEmptyScoresBO> options = new ArrayList<>();
            for (WorkFillOptionDO workFillOptionDO : workFillOptionDOList) {
                fillEmptyScoresBO fillEmptyScoresBO = new fillEmptyScoresBO();
                fillEmptyScoresBO.setOrder(workFillOptionDO.getOption());
                fillEmptyScoresBO.setScore(workFillOptionDO.getScore());
                options.add(fillEmptyScoresBO);
            }
            workFillEmptyBO.setOptions(options);

            workFillEmptyList.add(workFillEmptyBO);
        }
        workTestByWorkIdVO.setWorkFillEmptyList(workFillEmptyList);

        // 设置编程题，需要查询编程题表和编程题结果示例表
        List<WorkEncodeBO> workEncodeBOList = new ArrayList<>();
        List<EncodeWorkBO> workEncode = workEncodeMapper.getWorkEncode(workId);
        for (EncodeWorkBO EncodeWorkBO : workEncode) {
            WorkEncodeBO workEncodeBO = new WorkEncodeBO();
            Integer encodeId = EncodeWorkBO.getEncodeId();
            workEncodeBO.setId(encodeId);
            workEncodeBO.setScore(EncodeWorkBO.getScore());

            // 根据题目id查询出编程题全部数据
            EncodeQuestionDO encodeQuestionDO = encodeQuestionMapper.getById(encodeId);

            workEncodeBO.setQuestionNumber(encodeQuestionDO.getQuestionNumber());
            workEncodeBO.setChapter(encodeQuestionDO.getChapter());
            workEncodeBO.setTitle(encodeQuestionDO.getTitle());
            workEncodeBO.setDescription(encodeQuestionDO.getDescription());
            workEncodeBO.setSuggest(encodeQuestionDO.getSuggest());
            List<ResultExampleBO> list = new ArrayList<>();

            // 设置结果示例
            List<EncodeExampleDO> encodeExampleDOList = encodeExampleMapper.getAllByEncodeId(encodeId);
            for (EncodeExampleDO encodeExampleDO : encodeExampleDOList) {
                ResultExampleBO resultExampleBO = new ResultExampleBO();
                resultExampleBO.setInput(encodeExampleDO.getInput());
                resultExampleBO.setOutput(encodeExampleDO.getOutput().replace("#", "\n"));
                resultExampleBO.setExplain(encodeExampleDO.getExplain());
                list.add(resultExampleBO);
            }

            workEncodeBO.setResultExampleBOList(list);
            workEncodeBOList.add(workEncodeBO);
        }

        workTestByWorkIdVO.setWorkEncodeBOList(workEncodeBOList);
        return workTestByWorkIdVO;
    }

    // 编程题判断
    public List<JavaRunBO> encodeJudge(Integer userId, Integer encodeId,String className) {
        // 第一步，根据编程题id查询该题目的输入和输出参数，输入参数使用字符串数组代替
        List<EncodeTestDO> encodeTestDOList = encodeTestMapper.getListByEncodeId(encodeId);
        List<JavaRunBO> javaRunBOList = new ArrayList<>();

        // 构建循环，查询全部参数
        for (EncodeTestDO encodeTestDO : encodeTestDOList) {
            JavaRunBO javaRunBO = new JavaRunBO();

            // 1. 设置输出参数
            String output = encodeTestDO.getOutput();
            javaRunBO.setOutput(splitString(output, '#'));

            Integer encodeTestDOId = encodeTestDO.getId();
            //根据这个encodeTEstDOId获取输入参数信息
            String[] input = encodeTestDataMapper.getListByEncodeTestId(encodeTestDOId);
            // 2 .设置输入参数
            javaRunBO.setInput(input);

            // 3.构建标识符logo，用户在另一个服务器创建文件夹，保存这个class文件java文件和这个txt文件
            String logo = userId + "-" + encodeId + "-" + encodeTestDOId + UUID.randomUUID();
            javaRunBO.setLogo(logo);

            javaRunBOList.add(javaRunBO);
        }
        return javaRunBOList;
    }


    /**
     * 将这个字符串按照指定字符切割为字符串数组
     * @param input 字符串
     * @param delimiter 字符
     * @return 字符串数组
     */
    public static String[] splitString(String input, char delimiter) {
        List<String> resultList = new ArrayList<>();
        int startIndex = 0;
        for (int i = 0; i < input.length(); i++) {
            if (input.charAt(i) == delimiter) {
                if (startIndex < i) {
                    resultList.add(input.substring(startIndex, i));
                }
                startIndex = i + 1;
            }
        }
        // Add the last segment, if any
        if (startIndex < input.length()) {
            resultList.add(input.substring(startIndex));
        }
        return resultList.toArray(new String[0]);
    }
}
